﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Defect_Tracking_System.Models;
using Defect_Tracking_System.Helpers;
using Defect_Tracking_System.Controllers.ControllerExtensions;
using System.IO;

namespace Defect_Tracking_System.Controllers
{
    public class DefectController : Controller
    {
        DefectManagement DM = DefectManagement.GetInstance();
        public ProjectManagement PM = ProjectManagement.GetInstance();
        public AccountManagement AM = AccountManagement.GetInstance();
        public ClientManagement CM = ClientManagement.GetInstance();

        [Authorize]
        public ActionResult Index(string type = "All", int PageIndex = 1, string projectId = " ")
        {
            try
            {
                string UserName = User.Identity.Name;
                Account account = AM.GetUserByUserName(UserName);
                projectId = projectId == " " ? null : projectId;
                if (account == null || !account.IsActive || account.Role == "System Admin")
                {
                    ViewData["message"] = "you don't permission to access this page.";
                    return View("Error");
                }
                DefectListModel model;
                if (type != "All" && type != "MyDefect")
                {
                    ViewData["message"] = "Page not exist, please check your url.";
                    return View("Error");
                }
                else
                {
                    model = new DefectListModel(DM.GetDefects(projectId, User.Identity.Name, type), PageIndex, User.Identity.Name, projectId, type);
                    return View(model);
                }
            }
            catch (Exception ex)
            {
                ViewData["message"] = ex.Message;
                return View("Error");
            }
        }

        [Authorize, HttpPost]
        public ActionResult GetDefectInProject(FormCollection form)
        {
            try
            {
                string projectId = form["ProjectId"];
                string type = form["Type"];
                if (type != "All" && type != "MyDefect")
                    type = "All";
                var defect = DM.GetDefects(projectId, User.Identity.Name, type);
                DefectListModel model = new DefectListModel(defect, 1, User.Identity.Name, projectId, type);
                return Json(model);
            }
            catch (Exception ex)
            {
                ViewData["message"] = ex.Message;
                return View("Error");
            }
        }
        
        [Authorize]
        public ActionResult Create()
        {
            DefectModel Model = new DefectModel();

            return View(Model);
        }

        [Authorize, ValidateInput(false), HttpPost]
        public ActionResult Create(DefectModel Model)
        {       
            if (ModelState.IsValid)
            {
                Account account = AM.GetUserByUserName(User.Identity.Name);
                Model.Creator = account.AccountId.ToString();

                try
                {
                    DM.AddDefect(Model);
                    ViewData["Message"] = "Add Successfully.";
                }
                catch (Exception ex)
                {
                    ViewData["Message"] = ex.Message;
                }
            }
            
            return View(Model);
        }

        [Authorize]
        public ActionResult Edit(String DefectId, String ReturnUrl)
        {
            Session["AllowEditDefect"] = null;

            Defect defect = DM.GetDefect(DefectId);
            if (defect == null)
            {
                ViewData["Message"] ="Defect is not exited.";
                return View("Error");
            }

            if (!defect.Project.IsActive)
            {
                ViewData["Message"] = "Project is disable";
                return View("Error");
            }

            Account AccountLogin = AM.GetUserByUserName(User.Identity.Name);
            if (AccountLogin.AccountId != defect.Creator && AccountLogin.AccountId != defect.AssignedMember)
            {
                if (AccountLogin.Role == "Group Admin" || AccountLogin.Role == "Project Admin")
                {
                    Session["AllowEditDefect"] = true;
                }
                else
                {
                    ViewData["Message"] = "You don't have right to edit this defect";
                    return View("Error");
                }
            }
            else
            {
                Session["AllowEditDefect"] = true;
            }

            DefectModel Model = DM.GetDefectModel(DefectId);

            ViewData["ReturnUrl"] = ReturnUrl;
            return View(Model);
        }

        [Authorize, ValidateInput(false), HttpPost]
        public ActionResult Edit(String DefectId, DefectModel Model, String ReturnUrl)
        {
            Defect defect = DM.GetDefect(DefectId);
            if (defect == null)
            {
                ViewData["Message"] = "Defect is not exited";
                return View("Error");
            }

            if (!defect.Project.IsActive)
            {
                ViewData["Message"] = "Project is disable";
                return View("Error");
            }

            if (Session["AllowEditDefect"] == null)
            {
                ViewData["Message"] = "You don't have right to edit this defect.";
                return View("Error");
            }

            if (ModelState.IsValid)
            {
                try
                {
                    Model.DefectId = DefectId;
                    EmailNotification.GetIntance().BeginChangeDefect(DefectId, User.Identity.Name);
                    DM.EditDefect(Model);
                    EmailNotification.GetIntance().EndChangeDefect();
                    ViewData["Message"] = "Edit Successfully";
                }
                catch (Exception ex)
                {
                    ViewData["Message"] = ex.Message;
                }
            }
            ViewData["ReturnUrl"] = ReturnUrl;
            return View(Model);
        }

        [Authorize]
        public ActionResult Resolution(String DefectId, String ReturnUrl)
        {
            Defect defect = DM.GetDefect(DefectId);
            if (defect == null)
            {
                ViewData["Message"] = "Defect is not exited";
                return View("Error");
            }

            if (!defect.Project.IsActive)
            {
                ViewData["Message"] = "Project is disable";
                return View("Error");
            }

            Account AccountLogin = AM.GetUserByUserName(User.Identity.Name);
            if (AccountLogin.AccountId != defect.AssignedMember)
            {
                if (AccountLogin.Role == "Group Admin" || AccountLogin.Role == "Project Admin")
                {
                    Session["AllowEditDefect"] = true;
                }
                else
                {
                    ViewData["Message"] = "You don't have right to report resolution for this defect.";
                    return View("Error");
                }
            }
            else
            {
                Session["AllowEditDefect"] = true;
            }

            ResolutionModel Model = DM.GetResolutionModel(DefectId);

            ViewData["ReturnUrl"] = ReturnUrl;
            return View(Model);
        }

        [HttpPost,ValidateInput(false), Authorize]
        public ActionResult Resolution(String DefectId, ResolutionModel Model, String ReturnUrl)
        {
            Defect defect = DM.GetDefect(DefectId);
            if (defect == null)
            {
                ViewData["Message"] = "Defect is not exited";
                return View("Error");
            }

            if (Session["AllowEditDefect"] == null)
            {
                ViewData["Message"] = "You don't have right to report resolution for this defect.";
                return View("Error");
            }

            if (ModelState.IsValid)
            {
                try
                {
                    Model.DefectId = DefectId;
                    DM.EditResolution(Model);
                    ViewData["Message"] = "Report Successfully";
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }

            ViewData["ReturnUrl"] = ReturnUrl;
            return View(Model);
        }

        [Authorize]
        public ActionResult Details(string DefectId, int PageIndex)
        {
            try
            {
                string UserName = User.Identity.Name;
                Account account = AM.GetUserByUserName(UserName);
                Defect defect = DM.GetDefect(DefectId);
                if (defect != null)
                {
                    if (account == null || (account != null && !account.IsActive) || (account.Role == "User" && PM.GetProjectMember(account.AccountId.ToString(), defect.ProjectId.ToString()) == null) || account.Role == "System Admin")
                    {
                        ViewData["message"] = "Sorry, you don't permission to access this page.";
                        return View("Error");
                    }
                }
                else
                {
                    throw new Exception("Sorry, this defect not exist.");
                }
                DefectDetailsModel model = new DefectDetailsModel(DefectId, PageIndex);
                return View(model);
            }
            catch (Exception ex)
            {
                ViewData["message"] = ex.Message;
                return View("Error");
            }
        }

        [Authorize, ValidateInput(false), HttpPost]
        public ActionResult CommentOnDefect(FormCollection form)
        {
            try
            {
                string defectId = form["DefectId"];

                Defect defect = DM.GetDefect(defectId);

                if (defect == null)
                {
                    ViewData["Message"] = "Defect is not exited";
                    return View("Error");
                }

                if (!defect.Project.IsActive)
                {
                    ViewData["Message"] = "Project is disable";
                    return View("Error");
                }

                string cmt = form["comment"];
                Guid DefectId;
                if (Guid.TryParse(defectId, out DefectId))
                {
                    if (!String.IsNullOrEmpty(cmt))
                    {
                        Comment comment = new Comment();
                        comment.CommentId = Guid.NewGuid();
                        comment.Creator = AM.GetUserByUserName(User.Identity.Name).AccountId;
                        comment.Content = cmt;
                        comment.DefectId = DefectId;
                        comment.CreatedDate = DateTime.Now;
                        DM.AddCommentToDefect(comment);

                        EmailNotification.GetIntance().NotifyComment(comment.CommentId.ToString());
                    }
                }
                DefectDetailsModel model = new DefectDetailsModel(defectId, 1);
                return RedirectToAction("Details", new { DefectId = defectId, PageIndex = 1 });
            }
            catch (Exception ex)
            {
                ViewData["message"] = ex.Message;
                return View("Error");
            }
        }

        [Authorize]
        public ActionResult DeleteDefect(string defectId, int PageIndex, string Type)
        {

            try
            {
                string UserName = User.Identity.Name;
                Account user = AM.GetUserByUserName(UserName);
                Defect defect = DM.GetDefect(defectId);

                if (defect == null)
                {
                    ViewData["Message"] = "Defect is not exited";
                    return View("Error");
                }

                if (!defect.Project.IsActive)
                {
                    ViewData["Message"] = "Project is disable";
                    return View("Error");
                }

                if (user == null || (user != null && !user.IsActive) || (user != null && defect != null && user.Role == "User" && defect.Creator != user.AccountId) || user.Role == "System Admin")
                {
                    ViewData["message"] = "Sorry, you don't permission to delete this defect.";
                    return View("Error");
                }
                else
                {
                    DM.DeleteDefect(defect);
                    //DefectListModel model = new DefectListModel(DM.GetDefects(null, UserName, "All"), 1, UserName, null, "All");
                    return RedirectToAction("Index", new { type = Type, PageIndex = PageIndex });
                }
            }
            catch (Exception ex)
            {
                ViewData["message"] = ex.Message;
                return View("Error");
            }
        }

        [Authorize, HttpPost]
        public ActionResult DeleteDefect(FormCollection form)
        {
            try
            {
                string UserName = User.Identity.Name;
                Account user = AM.GetUserByUserName(UserName);
                if (user == null || (user != null && !user.IsActive) || user.Role == "User" || user.Role == "System Admin")
                {
                    ViewData["message"] = "Sorry, you don't permission to do this action.";
                    return View("Error");
                }
                else
                {
                    string defectIds = form["defectId"];
                    if (!String.IsNullOrEmpty(defectIds))
                    {
                        char[] splitVal = { ',' };
                        string[] DefectIds = defectIds.Split(splitVal);
                        foreach (string DefectId in DefectIds)
                        {
                            Defect defect = DM.GetDefect(DefectId);

                            if (defect.Project.IsActive)
                            {
                                DM.DeleteDefect(defect);
                            }
                           
                        }
                    }
                    int PageIndex = int.Parse(form["PageIndex"]);
                    string Type = form["TypeView"];
                    return RedirectToAction("Index", new { type = Type, PageIndex = PageIndex });
                }
            }
            catch (Exception ex)
            {
                ViewData["message"] = ex.Message;
                return View("Error");
            }
        }

        [Authorize, HttpPost]
        public ActionResult AttachFileToDefect(string id, int pageIndex, HttpPostedFileBase FileUpload)
        { 
            try
            {
                string UserName = User.Identity.Name;
                Account user = AM.GetUserByUserName(UserName);
                Defect defect = DM.GetDefect(id);

                if (defect == null)
                {
                    ViewData["Message"] = "Defect is not exited";
                    return View("Error");
                }

                if (!defect.Project.IsActive)
                {
                    ViewData["Message"] = "Project is disable";
                    return View("Error");
                }

                if (defect != null)
                {
                    if (user == null || (user != null && !user.IsActive) || (user != null && user.Role == "User" && (defect.Creator != user.AccountId || defect.AssignedMember != user.AccountId)) || user.Role == "System Admin")
                    {
                        throw new Exception("Sorry, you don't permission to do this action.");
                    }
                    //HttpPostedFileBase file = Request.Files[form["FileUpload"]] as HttpPostedFileBase;
                    if (FileUpload.ContentLength > 512000)
                    {
                        Session.Add("fileError", "File size don't greater than 500kb");
                    }
                    else
                    {
                        Guid DefectId;
                        if (Guid.TryParse(id, out DefectId))
                        {
                            Utilities util = new Utilities();
                            string ext = FileUpload.FileName.Substring(FileUpload.FileName.LastIndexOf("."));
                            string randomName = util.GenerateFileName(32, ext);
                            string path = HttpContext.Server.MapPath("/Attachment/" + randomName);
                            FileUpload.SaveAs(path);

                            Attachment attach = new Attachment();
                            attach.AttachId = Guid.NewGuid();
                            attach.DefectId = DefectId;
                            attach.FileName = FileUpload.FileName;
                            attach.Path = path;
                            attach.AttachDate = DateTime.Now;
                            attach.Size = (int)Math.Ceiling(FileUpload.ContentLength / (double)1024);
                            attach.Uploader = user.AccountId;
                            DM.AddAttachmentToDefect(attach);
                        }
                    }
                    return RedirectToAction("Details", new { DefectId = id, PageIndex = pageIndex });
                }
                else
                {
                    throw new Exception("Sorry, this defect not exist.");
                }
            }
            catch (Exception ex)
            {
                ViewData["message"] = ex.Message;
                return View("Error");
            }
        }

        public ActionResult DeleteAttachmentFromDefect(string id)
        {
            try
            {
                Account user = AM.GetUserByUserName(User.Identity.Name);
                Attachment attach = DM.GetAttachment(id);
                Defect defect = attach.Defect;

                if (defect == null)
                {
                    ViewData["Message"] = "Defct is not exited";
                    return View("Error");
                }

                if (!defect.Project.IsActive)
                {
                    ViewData["Message"] = "Project is disable";
                    return View("Error");
                }

                if (attach != null)
                {
                    if (user == null || (user != null && !user.IsActive) || (user != null && user.Role == "User" && (attach.Defect.Creator != user.AccountId || attach.Defect.AssignedMember != user.AccountId)) || user.Role == "System Admin")
                    {
                        throw new Exception("Sorry, you don't permission to do this action.");
                    }
                    DM.DeleteAttachmentFromDefect(attach);
                }
                return RedirectToAction("Details", new { DefectId = attach.DefectId.ToString(), PageIndex = 1 });
            }
            catch (Exception ex)
            {
                ViewData["message"] = ex.Message;
                return View("Error");
            }
        }

        public ActionResult CloseReopenDefect(string id, string act, string requesturl)
        {
            try
            {
                string UserName = User.Identity.Name;
                Account user = AM.GetUserByUserName(UserName);
                Defect defect = DM.GetDefect(id);

                if (defect == null)
                {
                    ViewData["Message"] = "Defct is not exited";
                    return View("Error");
                }

                if (!defect.Project.IsActive)
                {
                    ViewData["Message"] = "Project is disable";
                    return View("Error");
                }

                if (defect != null)
                {
                    if (user == null || (user != null && user.Role == "User" && defect.Creator != user.AccountId && defect.AssignedMember != user.AccountId) || user.Role == "System Admin")
                    {
                        throw new Exception("Sorry, you don't permission to do this action.");
                    }
                    else
                    {
                        EmailNotification.GetIntance().BeginChangeDefect(id, User.Identity.Name);
                        DM.CloseReopenDefect(id, act);
                        EmailNotification.GetIntance().EndChangeDefect();
                        
                    }
                    return Redirect(requesturl);
                }
                else
                {
                    throw new Exception("Sorry, this defect not exist.");
                }
            }
            catch(Exception ex)
            {
                ViewData["message"] = ex.Message;
                return View("Error");
            }
        }
		
        [Authorize]
        public ActionResult DownloadAttachment(string AttachmentId)
        {
            try
            {
                Attachment attach = DM.GetAttachment(AttachmentId);
                if (attach == null)
                {
                    throw new Exception("Sorry, this attachment not exist");
                }
                else
                {
                    string fileName = attach.FileName;
                    FileInfo file = new FileInfo(attach.Path);
                    if (file.Exists)
                    {
                        return File(attach.Path, "application",attach.FileName);
                    }
                    else
                    {
                        DM.DeleteAttachmentFromDefect(attach);
                        throw new Exception("Sorry, attachment not exist.");
                    }
                }
            }
            catch (Exception ex)
            {
                ViewData["message"] = ex.Message;
                return View("Error");
            }
        }

        [Authorize]
        public ActionResult SearchDefect(string keyWord, int PageIndex = 1)
        {
            try
            {
                ViewData["KeyWord"] = keyWord;
                DefectListModel model = new DefectListModel(DM.SearchDefect(keyWord, User.Identity.Name), PageIndex, User.Identity.Name, null, null);
                return View(model);
            }
            catch (Exception ex)
            {
                ViewData["message"] = ex.Message;
                return View("Error");
            }
        }

        [Authorize, HttpPost]
        public ActionResult Export(FormCollection form)
        {
            try
            {
                ReportManagement.DefectDoc Doc;
                if (String.IsNullOrEmpty(form["KeyWord"]))
                {
                    string projectId = form["ProjectId"];
                    string type = form["TypeView"];
                    Doc = new ReportManagement.DefectDoc(User.Identity.Name, projectId, type);
                }
                else
                {
                    string keyword = form["KeyWord"];
                    Doc = new ReportManagement.DefectDoc(User.Identity.Name, keyword);
                }
                return this.Excel("Defect.xlsx", "Defect", Doc.Datas, Doc.Headers, Doc.ColumnsName);
            }
            catch (Exception ex)
            {
                ViewData["message"] = ex.Message;
                return View("Error");
            }
        }
    }
}